import Link from "next/link";
import { notFound } from "next/navigation";
import { ArrowLeft, LifeBuoy } from "lucide-react";
import { ERROR_MESSAGES, type ErrorCode } from "@fetcha/core";
import { getWorkspace } from "@/lib/session";
import { formatBytes, formatDate, formatMs, formatUsd, timeAgo } from "@/lib/format";
import { getRequestDetail } from "@/lib/queries/dashboard";
import { PageHeader } from "@/components/ui/page-header";
import { Badge, StatusBadge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { CopyButton } from "@/components/ui/copy-button";
import { Alert } from "@/components/ui/alert";
import { RequestDetailTabs } from "@/components/dashboard/requests/request-detail-tabs";
import { TimingWaterfall } from "@/components/dashboard/requests/timing-waterfall";
import { AttemptsTimeline } from "@/components/dashboard/requests/attempts-timeline";
import { HeadersTables } from "@/components/dashboard/requests/headers-table";
import { HttpCode, NetworkLabel } from "@/components/dashboard/requests/requests-table";
export const dynamic = "force-dynamic";
function Row({ label, children, mono }: { label: string; children: React.ReactNode; mono?: boolean }) {
return (
{label}
{children}
);
}
export default async function RequestDetailPage({ params }: { params: Promise<{ id: string }> }) {
const [ws, { id }] = await Promise.all([getWorkspace(), params]);
if (!/^req_[A-Za-z0-9]{4,64}$/.test(id)) notFound();
const req = await getRequestDetail(ws.organization.id, id, { providerVisibility: ws.organization.providerVisibility });
if (!req) notFound();
const headerCount = Object.keys(req.requestHeaders ?? {}).length + Object.keys(req.responseHeaders ?? {}).length;
const errorHelp = req.errorCode && req.errorCode in ERROR_MESSAGES ? ERROR_MESSAGES[req.errorCode as ErrorCode] : null;
const otherProject = req.projectId !== ws.project.id;
const overview = (
Request
{req.url}
{req.finalUrl && req.finalUrl !== req.url ? (
{req.finalUrl}
) : null}
{req.method}
{req.domain}
{req.format}
{req.source}
{req.browser ? (
browser requested
) : null}
{req.projectName}
{otherProject ? (not the current project) : null}
{req.apiKey ? (
{req.apiKey.name}
{req.apiKey.prefix}…{req.apiKey.last4}
{req.apiKey.revoked ? revoked : null}
) : (
{req.source === "playground" ? "Playground (no key)" : "—"}
)}
{req.sessionId ? (
{req.sessionId}
) : (
none
)}
Routing and result
requested {req.requestedNetwork}
{[req.country, req.region, req.city].filter(Boolean).join(" · ") || any}
{formatMs(req.latencyMs)}
{req.attempts}
{formatBytes(req.bytesIn)} / {formatBytes(req.bytesOut)}
{formatUsd(req.priceUsd, true)}
{req.cached ? cached : null}
{req.errorCode ? (
{req.errorCode}
{req.errorMessage ? {req.errorMessage}
: null}
) : null}
{req.completedAt ? formatDate(req.completedAt, { timeStyle: "medium" }) : pending}
);
return (
Requests
{req.id}
}
description={
<>
{formatDate(req.createdAt, { timeStyle: "medium" })} ({timeAgo(req.createdAt)}) · {req.method} {req.domain}
>
}
actions={
}
/>
{req.status === "failed" && errorHelp ? (
{req.errorMessage ?? errorHelp}
{req.errorMessage && req.errorMessage !== errorHelp ? {errorHelp} : null}
) : null}
Attempts
Each route the router tried, in order. A blocked route escalates to another network or IP automatically.
}
headers={}
timing={}
/>
);
}